#ifndef LOSU_SHA384_H__
#define LOSU_SHA384_H__

/*
    使用方法
        1.创建SHA384_t
        2.放入void SHA382(SHA384_t *task)
        3.从SHA384_t.result得到结果
*/

#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef HASH_BLOCK_SIZE
#define HASH_BLOCK_SIZE         128 /* 1024 bits = 128 bytes */
#endif

#ifndef HASH_LEN_SIZE
#define HASH_LEN_SIZE           16  /* 128 bits =  16 bytes */
#endif

#ifndef HASH_LEN_OFFSET
#define HASH_LEN_OFFSET         112 /* 128 bytes - 16 bytes */
#endif

#ifndef HASH_ROUND_NUM
#define HASH_ROUND_NUM          80
#endif

typedef struct
{
    uint64_t high;  /*  high 64 bits */
    uint64_t low;   /*  low  64 bits */
} uint128_t;

typedef struct
{
    /*
        高层结构
    */
    const unsigned char *content;
    unsigned char result[97];
} SHA384_t;

/* SHA512 Constants */
static const uint64_t SHA384_K[HASH_ROUND_NUM] =
{
    0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
    0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118,
    0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2,
    0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694,
    0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65,
    0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5,
    0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4,
    0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70,
    0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF,
    0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B,
    0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30,
    0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8,
    0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8,
    0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3,
    0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC,
    0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B,
    0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178,
    0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B,
    0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C,
    0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817
};

/* Swap bytes in 64 bit value. 0x0123456789ABCDEF -> 0xEFCDAB8967452301*/
#define __bswap_64(x)               \
     ((((x) & 0xff00000000000000ull) >> 56)  \
     | (((x) & 0x00ff000000000000ull) >> 40) \
     | (((x) & 0x0000ff0000000000ull) >> 24) \
     | (((x) & 0x000000ff00000000ull) >>  8) \
     | (((x) & 0x00000000ff000000ull) <<  8) \
     | (((x) & 0x0000000000ff0000ull) << 24) \
     | (((x) & 0x000000000000ff00ull) << 40) \
     | (((x) & 0x00000000000000ffull) << 56))

#define ASSERT_RETURN_INT(x, d) if(!(x)) { return d; }

uint64_t Ch(uint64_t X, uint64_t Y, uint64_t Z);
uint64_t Maj(uint64_t X, uint64_t Y, uint64_t Z);
uint64_t ROTR(uint64_t X, uint64_t offset);
uint64_t SHR(uint64_t X, uint64_t offset);
uint64_t SIGMA0(uint64_t X);
uint64_t SIGMA1(uint64_t X);
uint64_t sigma0(uint64_t X);
uint64_t sigma1(uint64_t X);
int sha2_384(unsigned char *out, const unsigned char* in, const long long inlen);
void SHA384(SHA384_t *task);

#endif